import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


public class ClientHandler extends Thread
{
	private Socket clientSocket;
	private Connection connect;
	
	private InputStreamReader isr;
	private OutputStream os;

	boolean logIP = false;
	boolean loginComplete = false;
	int clientID;
	SharedObject sharedObject;
	
	//used for temperature
	public static boolean temp=false;
	
	public ClientHandler(Socket clientSocket,SharedObject sharedObject,int clientID)
	{
		this.clientSocket = clientSocket;
		this.sharedObject = sharedObject;
		this.clientID = clientID;
		
		sharedObject.addClient(clientSocket, clientID);
	}
	
	public void run()
	{
		try
		{	
			readDatabase();
			
			os = clientSocket.getOutputStream();
			isr = new InputStreamReader(clientSocket.getInputStream());
			
			BufferedReader br = new BufferedReader(isr);
			PrintWriter pw = new PrintWriter(os,true);
			
				//username = testman   password = 123 testman
				while(!loginComplete){
				//login 
					
					String login = br.readLine(); //get username:password
					String logInfo[] = login.split(":"); 
					
					System.out.println("Calling login method" + login);
					
					//Calling login method
					login(logInfo[0], logInfo[1]);
				}
				
				//logg the information about the connected user (ip adress)
				if (loginComplete == true) {
					if (logIP == false) {
						String tempIP = clientSocket.getInetAddress().toString().substring(1);
						Statement stmt = connect.createStatement();
						stmt.executeUpdate("INSERT INTO client_log (ip) VALUES ('" + tempIP + "');");
						System.out.println("HELLO LOGGING");
						logIP = true;
					}
				}
				
				while(!clientSocket.isClosed())
				{
				
				//excpects a device name with a state  example  bulb:on
				if(clientSocket.getInputStream().available()>0){
				
					System.out.println("Reading device");
					String device = br.readLine(); 
					
					if(device!=null){
					System.out.println("hh :"+device);
				}
					//if the user sends the command add: he/she want to add a device to the server
				if(device!=null && device.contains("add:")){
					
					String get[]=device.split(":");
					String add=get[1];
					Statement stmt1 = connect.createStatement();
					Statement stmt = connect.createStatement();
					ResultSet rs=stmt1.executeQuery("select * from devices where deviceName='" + add + "';");
					
					//if we find anything from the database, we don't need to add it
					if(rs.next()){
						
					}else{ //otherwise we just add it
						stmt.executeUpdate("insert into devices values(default,'" + add + "','off');");
						
					}
					sharedObject.addRemoveSoftwareDevice(clientSocket,clientID, device);
					
				} //sends the command to sharedobject that get the temp and send it back to it client
				else if(device!=null && device.equalsIgnoreCase("temp:in")){
					System.out.println("getting temperature from client");
					
					String[] parse = device.split(":");
					temp=true;
					sharedObject.sendInformationArdThenClient(clientSocket,clientID, parse[0] + ":" + parse[1]);		
				} //sends the ip of every user that is currently connected to the server
				else if(device!=null && device.equalsIgnoreCase("user:in")){
					System.out.println("Sending ip to client");
					
					pw.println(sharedObject.getClientIp());				
				} //handles oven
				else if(device!=null && device.equalsIgnoreCase("oven:on")){
                System.out.println("getting oven from client");
					
					String[] parse = device.split(":");
					temp=true;
					sharedObject.sendInformationToSoftwareThenClient(clientSocket,clientID, parse[0] + ":" + parse[1]);
					
				} //removes a device from the server (can be connected again through the client)
               else if(device!=null && device.contains("remove:")){
					
					String get[]=device.split(":");  //remove:deviceName
					String remove=get[1];
					Statement stmt1 = connect.createStatement();
					ResultSet rs=stmt1.executeQuery("select * from devices where deviceName='"+remove+"';");
					
					if(rs.next()){
						Statement stmt = connect.createStatement();
						
						stmt.executeUpdate("delete from devices WHERE deviceName='"+remove+"';");
					}
					
					sharedObject.addRemoveSoftwareDevice(clientSocket,clientID, device);	
					
				} //Reset, resets all the devices (to off state)
				else if (device!=null && device.equals("ligh:re")) {

					System.out.println("RESET");
					Statement stmt = connect.createStatement();
					Statement stmt1 = connect.createStatement();
					
					//ANDRINO
					ResultSet rs = stmt.executeQuery("SELECT * FROM devices WHERE state='on';");

					stmt1.executeUpdate("UPDATE devices SET state='off' WHERE state='on'");
					
					sharedObject.sendInformationArd(clientID, "ligh:re");
					sharedObject.sendInformationSoftware(clientID, "ligh:re");
					pw.println(device);
					
					//VIRTUAL
//					rs = stmt.executeQuery("SELECT deviceName FROM virtualdevices WHERE state='on';");
//					while (rs.next()) {
//						
//						stmt.executeUpdate("UPDATE virtualdevices SET state='off' WHERE deviceName='"+rs.getString(1)+"';");
//					}
					
				} //sends back the status of all the devices
				else if ( device!=null && device.equals("checklist"))
				{
					Statement stmt = connect.createStatement();
					
					String checkList ="";
					
					ResultSet rs = stmt.executeQuery("SELECT deviceName,state FROM devices;");
					while (rs.next()) {
						
						checkList = checkList + rs.getString(1) +":" + rs.getString(2) + ",";
					}
					
					
					//old code from when we hade the virtual devices table (in the database)
//					rs = stmt.executeQuery("SELECT deviceName,state FROM virtualDevices;");
//					
//					while (rs.next()) {
//						
//						checkList = checkList + rs.getString(1) +":" + rs.getString(2) + ",";
//					}
//					
					sharedObject.sendInformationSpecClient(clientID, checkList); // not yet implemented to 100%
										
				}//if we can't identify the command it must be a device that haven't been added
				else 
				{
					if(device!=null){
					String[] parse = device.split(":");  //split the devicename and state up
					
					System.out.println(device);
					
					System.out.println("Creating statement");
					
					//get the requested device and its current state
					Statement stmt = connect.createStatement();
					ResultSet rs=null;

					rs = stmt.executeQuery("SELECT deviceName,state FROM devices WHERE deviceName='" + parse[0] + "';");

					//point on the first row
					if(!rs.next())
					{
						sharedObject.sendInformationSoftware(clientID, parse[0] + ":" + parse[1]);
					
						stmt.executeUpdate("UPDATE virtualDevices SET state='" + parse[1] + "' WHERE deviceName='" + parse[0] + "';");

						pw.println("please add device");
						
					}//handles the regular requests from the client
					else 
					{
						 
						if((parse[1].equalsIgnoreCase("on")||parse[1].equalsIgnoreCase("off")) && rs.getString(2).equals(parse[1]))
						{
							//the state was not changed on the requested device
							System.out.println("Nothing happens");
							pw.println(parse[0] + " remains unchanged");
						}
						else
						{
							System.out.println(parse[0]);
							System.out.println(parse[1]);
							
							//check if the device if part of the virtual software
						if(device.equalsIgnoreCase("coffee:on")||device.contains("ac:")||device.equalsIgnoreCase("coffee:off")||device.contains("music:")||device.contains("oven:")||device.contains("video:")||device.contains("bulb:")){
						
							sharedObject.sendInformationSoftware(clientID, parse[0] + ":" + parse[1]);
							
							stmt.executeUpdate("UPDATE devices SET state='" + parse[1] + "' WHERE deviceName='" + parse[0] + "';");

							pw.println(device);
							
						} //the must standard approach to a standard request, change the state in the database and send the request to 
						else if(device!=null && !device.contains("temp:")){
							sharedObject.sendInformationArd(clientID, parse[0] + ":" + parse[1]);

							stmt.executeUpdate("UPDATE devices SET state='" + parse[1] + "' WHERE deviceName='" + parse[0] + "';");

							pw.println(parse[0] + ":" + parse[1]);
							}
						}
					}
				}
				}
				System.out.println("GOING ON");
					}
			}
			
			pw.close();
			br.close();
		}
		catch(Exception ie)
		{
			ie.printStackTrace();
			
			try 
			{	//if the thread crashes, then we need to remove the client from sharedObject since the client have disconnected
				sharedObject.removeClient(clientID);
				clientSocket.close();
			} 
			catch (IOException e) 
			{
				e.printStackTrace();
			}
		}
	}
	//creates a connection to the database
	public void readDatabase()
	{
		try 
		{
			//establish a connection the the database, username root and password 123
			Class.forName("com.mysql.jdbc.Driver");
			connect = DriverManager.getConnection("jdbc:mysql://localhost/projectdb", "root", "");
			Statement stmt = connect.createStatement();
			stmt.execute("USE projectdb");
		} 
		catch(SQLException e) 
		{
			e.printStackTrace();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	public void login(String userName, String password)
	{
		//comment if the login part is not needed
		//login part, will restart as long as the user put in the wrong username/password. 
			PrintWriter p=null;
			BufferedReader b = null;
			
			try {
				os = clientSocket.getOutputStream();
				
				p = new PrintWriter(os,true);
			
				System.out.println("Creating statement FOR THE LOGIN");
				Statement stmt = connect.createStatement();
				ResultSet rs = stmt.executeQuery("SELECT userName,password FROM users WHERE userName='" + userName + "' AND password='"+ password +"' ;");	
	
				//checks if we get any results from the SQL statement, if we haven't then the user doesn't exist, and the client have to try again
				//rs should only contain one row if it was successfull
				if(!rs.next())
				{
					System.out.println("NOTHING HERE");
					p.println("wrong");
				}
				else
				{
					System.out.println("User connected");
					loginComplete = true;
					p.println("accepted");
				}
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		
		//end of login part
	}
	
}
